// @HEADER
//*********************************************************************//
//  SiYuan: A numerical PDE solver                                     //
//  Copyright (2022) YUAN Xi                                           //
//  This Software is released under the BSD 2-Clause license detailed  //
//  in the file "LICENSE" in the top-level SiYuan directory            //
//*********************************************************************//
// @HEADER

#ifndef __Response_Base_hpp__
#define __Response_Base_hpp__

#include "Panzer_GlobalEvaluationData.hpp"
#include "PanzerDiscFE_config.hpp"
#include "Panzer_PhysicsBlock.hpp"
#include "Panzer_BC.hpp"
#include "Panzer_Traits.hpp"
#include "Panzer_WorksetDescriptor.hpp"
#include "Panzer_EvaluatorsRegistrar.hpp"

#include "Phalanx_FieldTag.hpp"

#include <string>

namespace SiYuan {


class ResponseBase : public panzer::GlobalEvaluationData_Default,
  public panzer::EvaluatorsRegistrar {
public:

   /** Only available constructor for this object.
     * This gurantees that the reponse object is
     * instantiatied with a name, and gives us basic
     * capability for name lookups.
     */
   ResponseBase(const std::string & responseName) :
    responseName_(responseName) {}

   virtual ~ResponseBase() {}

   /** Get the unmodified name for this response.
     */
   std::string getName() const { return responseName_; }

   /** Get the name of this response useful
     * for looking up data containers.
     */
   std::string getLookupName() const { return buildLookupName(responseName_); }

   /** Static member to build consistent look up names
     * based on a response name.
     */
   static std::string buildLookupName(const std::string & responseName)
   { return "RESPONSE_"+responseName; }

   //! Inherited from GlobalEvaluationData, 
   virtual void ghostToGlobal(int) 
   { scatterResponse(); }

   virtual void initializeData()
   { initializeResponse(); }

   //! Prepare the response for access by the user (do global communication)
   virtual void scatterResponse() = 0;

   virtual void initializeResponse() = 0;

   /** Build the response object used by this factory. This object
     * assumes the role of the scatter target and will be accessible
     * by all the evaluators in the field managers. This is the sideset
     * version of the buildResponseObject function.
     *
     * \param[in] responseName Name of response to be built. This
     *                         name will be used for looking up
     *                         the response in the <code>GlobalEvaluationDataContainer</code>
     *                         object.
     * \param[in] wkstdescs A vector of descriptors for the elements this response is over.
     */
   virtual Teuchos::RCP<ResponseBase> buildResponseObject(const std::string & responseName,
                        const std::vector<panzer::WorksetDescriptor> & wkstdescs) const = 0; 
   
   /** Build and register evaluators for a response on a particular physics
     * block.
     *
     * \param[in] responseName The name of the response to be constructed
     *                         by these evaluators.
     * \param[in,out] fm Field manager to be fuild with the evaluators.
     * \param[in] physicsBlock What physics block is being used for constructing
     *                         the evaluators
     * \param[in] user_data The user data parameter list, this stores things
     *                      that the user may find useful.
     */
   virtual void buildAndRegisterEvaluators(const std::string & responseName,
                                           PHX::FieldManager<panzer::Traits> & fm,
                                           const panzer::PhysicsBlock & physicsBlock,
                                           const Teuchos::ParameterList & user_data) const = 0;

   /** Is this evaluation type supported by the factory. This is used to determine cases
     * where a response may support a particular evaluation type, however at runtime the user
     * decides not to enable the (say) Jacobian evaluation of this response.
     *
     * Note that use of this mechanism is complementary to having the builder return 
     * <code>Teuchos::null</code> for a particular evaluation type.
     *
     * \note In this contect the "type" does not make a lot of sense. But in the dervied
     *       interface <code>ResponseEvaluatorFactory<EvalT></code> the type is the <code>EvalT</code>.
     *       Inclusion of this method here simply makes dynamic access to this method
     *       possible with out a cast. In the end it cleans up the code.
     */
   virtual bool typeSupported() const = 0;

private:

   std::string responseName_; 
 
   // hide these methods
   ResponseBase();
   ResponseBase(const ResponseBase &);
};

}

#endif
